import {AxiosPromise, AxiosRequestConfig, AxiosResponse} from '../types';
import {parseHeaders} from '../helpers/headers';
import { reject } from 'lodash';
import {createError} from '../helpers/error';

export default function xhr (config: AxiosRequestConfig): AxiosPromise {
  return new Promise((resolve) => {
    const {data = null, url, method = 'get', headers = {},responseType, timeout} = config;

    const request = new XMLHttpRequest();

    if (responseType) {
      request.responseType = responseType;
    }

    if (timeout) {
      request.timeout = timeout;
      request.ontimeout = function handleTimout () {
        reject(createError(
          `Timeout of ${config.timeout} ms exceeded`,
          config,
          `ECONNABORTED`,
          request
        ));
      }
    }
  
    request.onerror = function handleError () {
      reject(createError(
        'Network Error',
        config,
        null,
        request
      ));
    }
    request.open(method, url, true);

    request.onreadystatechange = function handleLoad() {
      if (request.readyState !== 4) {
        return;
      }

      if (request.status === 0) {
        return;
      }

      const responseHeaders = request.getAllResponseHeaders();
      const responseData = (responseType && responseType !== 'text') ? request.response : request.responseText;
      const response: AxiosResponse = {
        data: responseData,
        status: request.status,
        statusText: request.statusText,
        headers: parseHeaders(responseHeaders),
        config,
        request
      }

      handlerResponse(response);
    }
  
    Object.keys(headers).forEach((name) => {
      if (!data && name.toLowerCase() === 'content-type') {
        delete headers[name];
      } else {
        request.setRequestHeader(name, headers[name]);
      }
    })
  
    request.send(data);

    function handlerResponse (response: AxiosResponse) {
      if (response.status >= 200 && response.status < 300) {
        resolve(response);
      } else {
        reject(createError(
          `Request failed with status code ${response.status}`,
          config,
          null,
          request,
          response
        ));
      }
    }
  })

}